﻿#region Using Statements
using System;
using System.Collections.Generic;
using System.Text;
using starLiGHT.Physic.TwoD;
using Microsoft.Xna.Framework;

#endregion

#region COPYRIGHT

/*
    Copyright (c) 2008, 2009, 2010 
        Roland Rosenkranz (Glatzemann@email.de)
*/

#endregion

#region LICENSE

/*
    This file is part of starLiGHT.Collision.

    starLiGHT.Collision is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    starLiGHT.Collision is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with starLiGHT.Collision.  If not, see <http://www.gnu.org/licenses/>.

    
    ADDITIONAL (commercial) LICENSES for starLiGHT.Collision are available on request.
*/

#endregion

#region Version Stuff
// **************[ starLiGHT.Engine SVN ]**********************
// * $Rev:: 1486                  $:  Revision of last commit *
// * $Author:: glatzemann         $:  Author of last commit   *
// * $Date:: 2010-10-08 15:55:47 #$:  Date of last commit     *
// ************************************************************
#endregion

namespace starLiGHT.Physic
{
    public class RigidBody2D
    {
        Body body;

        public RigidBody2D(Body body)
        {
            this.body = body;
        }

        public bool Sleeping
        {
            get { return !body.Awake; }
        }

        /// <summary>
        /// Returns the position of the body's origin. 
        /// </summary>
        public Vector2 Position
        {
            get { return body.Position; }
            set { body.SetTransform(value, body.Angle); }
        }

        /// <summary>
        /// Returns the body's orientation in radians.
        /// </summary>
        public float Angle
        {
            get { return body.Angle; }
            set { body.SetTransform(body.Position, value); }
        }

        /// <summary>
        /// Grants access to the underlying Body of the physic system
        /// </summary>
        public Body Body
        {
            get { return body; }
        }

        public bool Bullet
        {
            get { return body.Bullet; }
            set { body.Bullet = value; }
        }

        public Vector2 LinearVelocity
        {
            get { return body.LinearVelocity; }
            set { body.LinearVelocity = value; }
        }

        public float LinearDamping
        {
            get { return body.LinearDamping; }
            set { body.LinearDamping = value; }
        }

        public float AngularVelocity
        {
            get { return body.AngularVelocity; }
            set { body.AngularVelocity = value; }
        }

        public float AngularDamping
        {
            get { return body.AngularDamping; }
            set { body.AngularDamping = value; }
        }

        public void SetTransform(Vector2 position, float angle)
        {
            body.SetTransform(position, angle);
        }

        /// <summary>
        /// Gets or sets the body type of this rigid body to one of this values:<br/>
        /// <br/>
        /// STATIC    - a static body does not move and behaves as if it has infinite mass. Static bodies can 
        ///             be moved manually by the user. A static body has always zero velocity and never collides 
        ///             with static or kinematic bodies.<br/>
        /// KINEMATIC - a kinematic body moves accoding to its velocity and never responses to forces. Normally 
        ///             kinematic bodies are moved by setting its velocity but you can move them manually. They never 
        ///             collide with other kinematic or static bodies.<br/>
        /// DYNAMIC   - is a dynamic body that is fully simulated by the engine and are moving according to its forces. It
        ///             will collide with all other body types and always have a finite, non-zero mass.<br/>
        /// </summary>
        public BodyType BodyType
        {
            get { return body.Type; }
            set { body.Type = value; }
        }

        /// <summary>
        /// Restitution make objects bounce. Usually this value should be set to be between 0.0f and 1.0f. 
        /// Consider dropping a ball on the ground. A value of zero means the ball won't bounce which is 
        /// called inelastic collision. A value of one will let the ball bounce without loosing velocity.
        /// </summary>
        public float Restitution
        {
            get
            {
                return body.FixtureList.GetRestitution();
            }
            set
            {
                for (Fixture f = body.FixtureList; f != null; f = f.m_next)
                {
                    f.SetRestitution(value);
                }
            }
        }

        public Fixture addBox(float x, float y, float width, float height) { return addBox(x, y, width, height, Vector2.Zero, 0.0f, 1.0f); }
        public Fixture addBox(float x, float y, float width, float height, Vector2 center, float angle, float density)
        {
            PolygonShape shape = new PolygonShape();
            shape.SetAsBox(width, height, center, angle);

            for (int i = 0; i < shape.m_vertices.Length; i++)
            {
                shape.m_vertices[i].X += x;
                shape.m_vertices[i].Y += y;
            }

            return body.CreateFixture(shape, density);
        }

        public Fixture addPolygon(params Vector2[] vertices) { return addPolygon(0.0f, vertices); }
        public Fixture addPolygon(float density, params Vector2[] vertices)
        {
            PolygonShape shape = new PolygonShape();
            shape.Set(vertices, vertices.Length);

            return body.CreateFixture(shape, density);
        }

        public Fixture addCircle(float x, float y, float radius)
        {
            CircleShape shape = new CircleShape();
            shape.m_radius = radius;
            shape.m_p = new Vector2(x, y);
            return body.CreateFixture(shape, 1.0f);
        }

        public Fixture addCircle(float x, float y, float radius, float density)
        {
            CircleShape shape = new CircleShape();
            shape.m_radius = radius;
            shape.m_p = new Vector2(x, y);
            return body.CreateFixture(shape, density);
        }

        public Fixture addEdgeShape(Vector2 start, Vector2 end) { return addEdgeShape(start, end, 0.0f, 1.0f); }
        public Fixture addEdgeShape(Vector2 start, Vector2 end, float density, float restitution)
        {
            EdgeShape shape = new EdgeShape();
            shape.Set(start, end);

            FixtureDef sd = new FixtureDef();
            sd.shape = shape;
            sd.density = density;
            sd.restitution = restitution;

            return body.CreateFixture(sd);
        }

        public void WakeUp()
        {
            body.Awake = true;
        }

        //public override RectangleF BoundingBox
        //{
        //    get 
        //    { 
        //        RectangleF rect = RectangleF.Empty;

        //        for (Fixture f = body.FixtureList; f != null; f = f.GetNext())
        //        {
        //            AABB aabb = f.GetAABB(0);
        //            rect = RectangleF.Union(rect, RectangleF.FromPoints(new Vector2[] { aabb.lowerBound, aabb.upperBound}));
        //        }

        //        return rect;
        //    }
        //}

        //public override float BoundingRadius
        //{
        //    get 
        //    {
        //        float BoundingRadius = 0f;

        //        for (Fixture f = body.FixtureList; f != null; f = f.GetNext())
        //        {
        //            BoundingRadius = System.Math.Max(f.GetShape().m_radius, BoundingRadius);
        //        }

        //        return BoundingRadius;
        //    }
        //}
    }

}
